home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 03 - Advanced Graphics / Example 3 / sprite.c < prev    next >
Text File  |  1995-02-27  |  9KB  |  310 lines

  1. //
  2. //    File: sprite.c
  3. //
  4. //    This file contains the routines to draw the sprites
  5. //
  6. //    2/19/95 -- Created by Mick
  7. //
  8.  
  9. // include files
  10.  
  11. #include "global.h"
  12.  
  13. #include "sprite.h"
  14.  
  15. #include "main.h"
  16.  
  17. // defines for this file
  18.  
  19. #define kClearColor 0            // the clear color in this case is white
  20.  
  21. // global function declarations
  22.  
  23. tSpriteInfo *loadSprite( signed short inSpriteResID );
  24. void disposeSprite( tSpriteInfo *inSpriteInfo );
  25. void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap );
  26. void endSpriteDraw( void );
  27. void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere );
  28.  
  29. // global data owned by this file
  30.  
  31. // local function declarations
  32.  
  33. static void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
  34. static void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
  35.  
  36. // static data
  37.  
  38. Rect sClipRect;                                                // the rectangle to clip to
  39. PixMapHandle sDestPixMap;        // where we are going to draw this data
  40. unsigned long sRowBytes;                // the row bytes of the pixmap
  41. unsigned char *sBaseAddr;            // the base address of the pixmap
  42.  
  43. // functions
  44.  
  45. //
  46. //    loadSprite -
  47. //
  48. //    Loads/allocates all the data for a sprite.
  49. //
  50.  
  51. tSpriteInfo *loadSprite( signed short inSpriteResID )
  52. {
  53.     tSpriteInfo *newSprite;            // the new sprite data
  54.     PicHandle spritePict;                        // the sprite/mask picture
  55.     CGrafPtr oldCPort;                    // the graf port that is in place when we are called
  56.     GDHandle oldDevice;            // the gdevice that is in place when we are called
  57.     
  58.     // create the sprite info record
  59.     newSprite = ( tSpriteInfo * )NewPtr( sizeof( tSpriteInfo ) );
  60.     
  61.     // load the pict
  62.     spritePict = GetPicture( inSpriteResID );
  63.     if ( spritePict == ( PicHandle )kNil )
  64.         {
  65.             // if it did not load, drop into the debugger -- real programs would have error checking
  66.             Debugger();
  67.         }
  68.     
  69.     // copy its bounds rect
  70.     newSprite->fSpriteRect = ( *spritePict )->picFrame;
  71.     
  72.     // create a gworld for it
  73.     NewGWorld( &newSprite->fSpriteWorld, 8, &( newSprite->fSpriteRect ), 
  74.             gAppColorTable, ( GDHandle )kNil, keepLocal );
  75.     
  76.     // extract the pixmap handle
  77.     newSprite->fSpritePix = GetGWorldPixMap( newSprite->fSpriteWorld );
  78.     
  79.     // save the current port and gdevice
  80.     GetGWorld( &oldCPort, &oldDevice );
  81.     
  82.     // set the offscreen buffer as current ( and lock the pixel map )
  83.     SetGWorld( newSprite->fSpriteWorld, ( GDHandle )kNil );
  84.     LockPixels( newSprite->fSpritePix );
  85.     
  86.     // draw the picture
  87.     EraseRect( &( newSprite->fSpriteRect ) );
  88.     DrawPicture( spritePict, &( newSprite->fSpriteRect ) );
  89.     
  90.     // restore the current port and gdevice
  91.     UnlockPixels( newSprite->fSpritePix );
  92.     SetGWorld( oldCPort, oldDevice );
  93.  
  94.     // dump the pict
  95.     ReleaseResource( ( Handle )spritePict );
  96.     
  97.     // return the new sprite!
  98.     return newSprite;
  99. }
  100.  
  101.  
  102. //
  103. //    disposeSprite -
  104. //
  105. //    Disposes/releases all the memory used in a sprite
  106. //
  107.  
  108. void disposeSprite( tSpriteInfo *inSpriteInfo )
  109. {
  110.     // dump the gworld
  111.     DisposeGWorld( inSpriteInfo->fSpriteWorld );
  112.     
  113.     // free the structure
  114.     DisposePtr( ( Ptr )inSpriteInfo );
  115. }
  116.  
  117.  
  118. //
  119. //    startSpriteDraw -
  120. //
  121. //    Prepare the sprite draw. Assumes that the port is set to the destination port.
  122. //
  123.  
  124. void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap )
  125. {
  126.     // set the clip region to be the passed in rect
  127.     sClipRect = *inClipRect;
  128.     
  129.     // save the pix map info (so we can use it)
  130.     sDestPixMap = inDestPixMap;
  131.  
  132.     // extract the needed information from the pixmap
  133.     sBaseAddr = ( unsigned char * )GetPixBaseAddr( sDestPixMap );
  134.     sRowBytes = ( *sDestPixMap )->rowBytes & 0x3FFF;
  135. }
  136.  
  137.  
  138. //
  139. //    endSpriteDraw -
  140. //
  141. //    End the sprite draw sequence.
  142. //
  143.  
  144. void endSpriteDraw( void )
  145. {
  146. }
  147.  
  148.  
  149. //
  150. //    drawSprite -
  151. //
  152. //    Draw the sprite in the port.
  153. //
  154.  
  155. void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere )
  156. {
  157.     Rect destRect;        // where we want to draw the sprite
  158.     
  159.     // calculate the destination rect
  160.     destRect = inSpriteInfo->fSpriteRect;
  161.     OffsetRect( &destRect, inWhere.h, inWhere.v );
  162.     
  163.     // determine if the spite needs to be drawn at all
  164.     if( destRect.top >= sClipRect.bottom || destRect.bottom <= sClipRect.top ||
  165.             destRect.left >= sClipRect.right || destRect.right <= sClipRect.left )
  166.         {
  167.             // no need to draw, goodbye
  168.             return;
  169.         }
  170.     
  171.     // determine if the sprite will be clipped
  172.     if ( destRect.top < sClipRect.top || destRect.bottom > sClipRect.bottom ||
  173.             destRect.left < sClipRect.left || destRect.right > sClipRect.right )
  174.         {
  175.             // handle the clipped case
  176.             renderSpriteClipped( inSpriteInfo, &destRect );
  177.         }
  178.     else
  179.         {
  180.             // handle the unclipped case
  181.             renderSpriteUnclipped( inSpriteInfo, &destRect );
  182.         }
  183. }
  184.  
  185.  
  186. //
  187. //    renderSpriteClipped -
  188. //
  189. //    Draw the spite, deal with clipping.
  190. //
  191.  
  192. void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
  193. {
  194.     Rect srcRect;                            // the rect that defines the clipped shape (source coordinates)
  195.     Rect destRect;                            // the rect that defines the clipped shape (destination coodinates)
  196.     unsigned char *srcPtr;                // our current position in the shape
  197.     unsigned char *destPtr;            // our current position in the destination
  198.     unsigned long srcRowBytes;        // the row bytes of the source data
  199.     unsigned char *srcBaseAddr;    // the base address of the source data
  200.     unsigned char *srcRowStart;    // the start of the current row in the source
  201.     unsigned char *destRowStart;    // the start of the current row in the destination
  202.     unsigned long xCounter;                // a counter to scan the row
  203.     unsigned long yCounter;                // a counter to scan the column
  204.     
  205.     // create a clipped rect in the coordinates of the sprite
  206.     srcRect.left = inDestRect->left < sClipRect.left ? sClipRect.left - inDestRect->left : 0;
  207.     srcRect.right = inDestRect->right > sClipRect.right ? sClipRect.right - inDestRect->left : inDestRect->right - inDestRect->left;
  208.     srcRect.top = inDestRect->top < sClipRect.top ? sClipRect.top - inDestRect->top : 0;
  209.     srcRect.bottom = inDestRect->bottom > sClipRect.bottom ? sClipRect.bottom - inDestRect->top : inDestRect->bottom - inDestRect->top;
  210.     
  211.     // create the same rect in the coordinates of the destination
  212.     destRect.left = inDestRect->left + srcRect.left;
  213.     destRect.right = inDestRect->left + srcRect.right;
  214.     destRect.top = inDestRect->top + srcRect.top;
  215.     destRect.bottom = inDestRect->top + srcRect.bottom;
  216.     
  217.     // lock down the pixmap for the sprite
  218.     LockPixels( inSpriteInfo->fSpritePix );
  219.     
  220.     // extract the needed information from the pixmap
  221.     srcBaseAddr = ( unsigned char * )GetPixBaseAddr( inSpriteInfo->fSpritePix );
  222.     srcRowBytes = ( *( inSpriteInfo->fSpritePix ) )->rowBytes & 0x3FFF;
  223.     
  224.     // determine the starting pointers
  225.     srcRowStart = srcBaseAddr + srcRect.top * srcRowBytes + srcRect.left;
  226.     destRowStart = sBaseAddr + destRect.top * sRowBytes + destRect.left;
  227.     
  228.     // loop through the data
  229.     for( yCounter = srcRect.bottom - srcRect.top; yCounter > 0; yCounter-- )
  230.         {
  231.             // set the scanning pointers
  232.             srcPtr = srcRowStart;
  233.             destPtr = destRowStart;
  234.             
  235.             // draw this row
  236.             for( xCounter = srcRect.right - srcRect.left; xCounter > 0; xCounter-- )
  237.                 {
  238.                     if ( *srcPtr != kClearColor )
  239.                         {
  240.                             *destPtr = *srcPtr;
  241.                         }
  242.                     destPtr++;
  243.                     srcPtr++;
  244.                 }
  245.                 
  246.             // move to the next row
  247.             srcRowStart += srcRowBytes;
  248.             destRowStart += sRowBytes;
  249.         }
  250.     
  251.     // unlock the pixels
  252.     UnlockPixels( inSpriteInfo->fSpritePix );
  253. }
  254.  
  255.  
  256. //
  257. //    renderSpriteUnclipped -
  258. //
  259. //    Draw the sprite, no clipping needed
  260. //
  261.  
  262. void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
  263. {
  264.     unsigned char *srcPtr;                // our current position in the shape
  265.     unsigned char *destPtr;            // our current position in the destination
  266.     unsigned long srcRowBytes;        // the row bytes of the source data
  267.     unsigned char *srcBaseAddr;    // the base address of the source data
  268.     unsigned char *srcRowStart;    // the start of the current row in the source
  269.     unsigned char *destRowStart;    // the start of the current row in the destination
  270.     unsigned long xCounter;                // a counter to scan the row
  271.     unsigned long yCounter;                // a counter to scan the column
  272.     
  273.     // lock down the pixmap for the sprite
  274.     LockPixels( inSpriteInfo->fSpritePix );
  275.     
  276.     // extract the needed information from the pixmap
  277.     srcBaseAddr = ( unsigned char * )GetPixBaseAddr( inSpriteInfo->fSpritePix );
  278.     srcRowBytes = ( *( inSpriteInfo->fSpritePix ) )->rowBytes & 0x3FFF;
  279.     
  280.     // determine the starting pointers
  281.     srcRowStart = srcBaseAddr;
  282.     destRowStart = sBaseAddr + inDestRect->top * sRowBytes + inDestRect->left;
  283.     
  284.     // loop through the data
  285.     for( yCounter = inSpriteInfo->fSpriteRect.bottom; yCounter > 0; yCounter-- )
  286.         {
  287.             // set the scanning pointers
  288.             srcPtr = srcRowStart;
  289.             destPtr = destRowStart;
  290.             
  291.             // draw this row
  292.             for( xCounter = inSpriteInfo->fSpriteRect.right; xCounter > 0; xCounter-- )
  293.                 {
  294.                     if ( *srcPtr != kClearColor )
  295.                         {
  296.                             *destPtr = *srcPtr;
  297.                         }
  298.                     destPtr++;
  299.                     srcPtr++;
  300.                 }
  301.                 
  302.             // move to the next row
  303.             srcRowStart += srcRowBytes;
  304.             destRowStart += sRowBytes;
  305.         }
  306.     
  307.     // unlock the pixels
  308.     UnlockPixels( inSpriteInfo->fSpritePix );
  309. }
  310.